import React, { useState, useCallback, useRef } from 'react'
import { Button } from '@/components/ui/button'
import { Progress } from '@/components/ui/progress'
import { Alert, AlertDescription } from '@/components/ui/alert'
import {
  UploadCloud,
  X,
  File as FileIcon,
  Image as ImageIcon,
  AlertCircle,
  CheckCircle2,
} from 'lucide-react'

interface FileStatus {
  id: string
  file: File
  progress: number
  status: 'pending' | 'uploading' | 'success' | 'error'
  error?: string
  url?: string
}

interface UploadProps {
  /** 是否支持多文件上传 */
  multiple?: boolean
  /** 是否自动上传 */
  autoUpload?: boolean
  /** 接受的文件类型 */
  accept?: string
  /** 最大文件大小(bytes) */
  maxSize?: number
  /** 最大文件数量 */
  maxCount?: number
  /** 是否支持拖拽上传 */
  draggable?: boolean
  /** 是否显示文件列表 */
  showFileList?: boolean
  /** 自定义上传方法 */
  customRequest?: (
    file: File,
    onProgress: (percent: number) => void,
  ) => Promise<string>
  /** 上传前校验 */
  beforeUpload?: (file: File) => boolean | Promise<boolean>
  /** 文件列表改变回调 */
  onChange?: (files: FileStatus[]) => void
  /** 上传成功回调 */
  onSuccess?: (file: FileStatus) => void
  /** 上传失败回调 */
  onError?: (file: FileStatus) => void
  /** 文件删除回调 */
  onRemove?: (file: FileStatus) => void
  /** 自定义文件预览 */
  itemRender?: (file: FileStatus) => React.ReactNode
  /** 额外的提示文本 */
  hint?: string
}

// 默认的文件上传方法
const defaultRequest = async (
  file: File,
  onProgress: (percent: number) => void,
): Promise<string> => {
  // 模拟上传进度
  return new Promise((resolve) => {
    let percent = 0
    const interval = setInterval(() => {
      percent += 10
      onProgress(percent)
      if (percent >= 100) {
        clearInterval(interval)
        resolve(URL.createObjectURL(file))
      }
    }, 100)
  })
}

export const Upload: React.FC<UploadProps> = ({
  multiple = false,
  autoUpload = true,
  accept,
  maxSize = 50 * 1024 * 1024, // 默认50MB
  maxCount,
  draggable = true,
  showFileList = true,
  customRequest = defaultRequest,
  beforeUpload,
  onChange,
  onSuccess,
  onError,
  onRemove,
  itemRender,
  hint,
}) => {
  const [fileList, setFileList] = useState<FileStatus[]>([])
  const [isDragging, setIsDragging] = useState(false)
  const [globalError, setGlobalError] = useState<string>()
  const inputRef = useRef<HTMLInputElement>(null)

  // 生成唯一ID
  const generateId = () => Math.random().toString(36).slice(2)

  // 处理文件大小校验
  const validateSize = (file: File): boolean => {
    if (file.size > maxSize) {
      setGlobalError(`文件大小不能超过 ${Math.round(maxSize / 1024 / 1024)}MB`)
      return false
    }
    return true
  }

  // 处理文件数量校验
  const validateCount = (count: number): boolean => {
    if (maxCount && fileList.length + count > maxCount) {
      setGlobalError(`最多只能上传 ${maxCount} 个文件`)
      return false
    }
    return true
  }

  // 处理文件上传
  const handleUpload = async (file: FileStatus) => {
    try {
      if (beforeUpload) {
        const shouldUpload = await beforeUpload(file.file)
        if (!shouldUpload) return
      }

      const newFileList = fileList.map((item) =>
        item.id === file.id ? { ...item, status: 'uploading' as const } : item,
      )
      setFileList(newFileList)
      onChange?.(newFileList)

      const url = await customRequest(file.file, (percent) => {
        const updatedFiles = fileList.map((item) =>
          item.id === file.id ? { ...item, progress: percent } : item,
        )
        setFileList(updatedFiles)
        onChange?.(updatedFiles)
      })

      const successFile = { ...file, status: 'success' as const, url }
      const finalFiles = fileList.map((item) =>
        item.id === file.id ? successFile : item,
      )
      setFileList(finalFiles)
      onChange?.(finalFiles)
      onSuccess?.(successFile)
    } catch (error) {
      const errorFile = {
        ...file,
        status: 'error' as const,
        error: error instanceof Error ? error.message : '上传失败',
      }
      const errorFiles = fileList.map((item) =>
        item.id === file.id ? errorFile : item,
      )
      setFileList(errorFiles)
      onChange?.(errorFiles)
      onError?.(errorFile)
    }
  }

  // 处理文件选择
  const handleFiles = async (files: FileList | null) => {
    if (!files?.length) return

    setGlobalError(undefined)
    if (!validateCount(files.length)) return

    const newFiles: FileStatus[] = Array.from(files)
      .filter(validateSize)
      .map((file) => ({
        id: generateId(),
        file,
        progress: 0,
        status: 'pending',
      }))

    const updatedFiles = [...fileList, ...newFiles]
    setFileList(updatedFiles)
    onChange?.(updatedFiles)

    if (autoUpload) {
      newFiles.forEach(handleUpload)
    }
  }

  // 处理文件选择按钮点击
  const handleClick = () => {
    inputRef.current?.click()
  }

  // 处理文件输入变化
  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    handleFiles(e.target.files)
    // 重置 input 值，确保能重复选择相同文件
    if (inputRef.current) {
      inputRef.current.value = ''
    }
  }

  // 处理拖拽相关事件
  const handleDragEnter = useCallback((e: React.DragEvent<HTMLDivElement>) => {
    e.preventDefault()
    e.stopPropagation()
    setIsDragging(true)
  }, [])

  const handleDragLeave = useCallback((e: React.DragEvent<HTMLDivElement>) => {
    e.preventDefault()
    e.stopPropagation()
    setIsDragging(false)
  }, [])

  const handleDrop = useCallback((e: React.DragEvent<HTMLDivElement>) => {
    e.preventDefault()
    e.stopPropagation()
    setIsDragging(false)
    handleFiles(e.dataTransfer.files)
  }, [])

  // 处理文件删除
  const handleRemove = (file: FileStatus) => {
    const newFiles = fileList.filter((item) => item.id !== file.id)
    setFileList(newFiles)
    onChange?.(newFiles)
    onRemove?.(file)
  }

  // 获取文件图标
  const getFileIcon = (file: File) => {
    if (file.type.startsWith('image/')) {
      return <ImageIcon className="w-5 h-5" />
    }
    return <FileIcon className="w-5 h-5" />
  }

  // 默认的文件项渲染
  const defaultItemRender = (file: FileStatus) => (
    <div className="flex items-center gap-2 p-2 bg-gray-50 rounded-lg">
      {getFileIcon(file.file)}
      <div className="flex-1 min-w-0">
        <div className="flex items-center justify-between">
          <span className="truncate text-sm">{file.file.name}</span>
          <Button
            variant="ghost"
            size="icon"
            className="h-6 w-6"
            onClick={() => handleRemove(file)}
          >
            <X className="h-4 w-4" />
          </Button>
        </div>
        {file.status === 'uploading' && (
          <Progress value={file.progress} className="h-1" />
        )}
        {file.status === 'error' && (
          <span className="text-xs text-red-500">{file.error}</span>
        )}
      </div>
      {file.status === 'success' && (
        <CheckCircle2 className="w-4 h-4 text-green-500" />
      )}
      {file.status === 'error' && <AlertCircle className="w-4 h-4 text-red-500" />}
    </div>
  )

  return (
    <div className="w-full">
      <input
        ref={inputRef}
        type="file"
        accept={accept}
        multiple={multiple}
        onChange={handleChange}
        className="hidden"
      />

      {/* 拖拽区域 */}
      <div
        onClick={handleClick}
        onDragEnter={draggable ? handleDragEnter : undefined}
        onDragOver={draggable ? handleDragEnter : undefined}
        onDragLeave={draggable ? handleDragLeave : undefined}
        onDrop={draggable ? handleDrop : undefined}
        className={`
          w-full h-32 border-2 border-dashed rounded-lg
          flex flex-col items-center justify-center gap-2
          bg-white transition-colors cursor-pointer
          ${isDragging ? 'border-primary bg-primary/5' : 'border-gray-200'}
        `}
      >
        <UploadCloud className="w-8 h-8 text-gray-400" />
        <div className="text-sm text-gray-500">
          <span className="text-primary">点击上传</span>
          {draggable && <span> 或拖拽文件到此处</span>}
        </div>
        {hint && <p className="text-xs text-gray-400">{hint}</p>}
      </div>

      {/* 错误提示 */}
      {globalError && (
        <Alert variant="destructive" className="mt-2">
          <AlertDescription>{globalError}</AlertDescription>
        </Alert>
      )}

      {/* 文件列表 */}
      {showFileList && fileList.length > 0 && (
        <div className="mt-4 space-y-2">
          {fileList.map((file) => (
            <div key={file.id}>
              {itemRender ? itemRender(file) : defaultItemRender(file)}
            </div>
          ))}
        </div>
      )}
    </div>
  )
}

export default Upload
